#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <stdint.h>
#include <algorithm>
#include <regex>
#include <unistd.h>
#include <cstring>
#include <assert.h>
#include <functional>
#include<memory>
#include <any>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <unordered_map>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <thread>
#include <mutex>
#include<condition_variable>
#include<signal.h>

// 复习正则表达式 regex
//  int main()
//  {
//      // std::string str = "GET /zjx/heoolworld/login?user=1234&pass=111111 HTTP/1.1\r\n";
//      std::string str = "GET /zjx/heoolworld/login HTTP/1.1\r\n";
//      std::regex e("(GET|POST|PUT|HEAD|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?: \n|\r\n)?");

//     //bool regex_mathch = (所要匹配的原字符串，将匹配的结果放在smatch 数组当中，正则表达式)
//     std::smatch matches;
//     bool ret = std::regex_match(str , matches , e);
//     if(ret == false)
//     {
//         return -1;
//     }
//     //遍历matches 将数据打印出来
//     for(auto & s: matches)
//     {
//         std::cout << s << std::endl;
//     }
//     return 0;
// }

// 复习通用类型any
// class Any
// {
// private:
//     // 通过多态来实现Any类型可以存储不同类型的数据，Any不能实现为模版
//     // 父类，利用父类指针指向子类对象，子类实现为模版用来存储不同类型的数据
//     class holder
//     {
//     public:
//         virtual ~holder() {}
//         virtual const std::type_info &type() = 0;
//         virtual holder *clone() = 0;
//     };
//     template <class T>
//     class placeholder : public holder
//     {
//     public:
//         T _val;

//     public:
//         placeholder(const T &val) : _val(val) {}
//         const std::type_info &type() override
//         {
//             return typeid(T);
//         }
//         holder *clone() override
//         {
//             return new placeholder(_val);
//         }
//     };

//     // 指向数据的指针
//     holder *_content;

// private:
//     Any &Swap(Any &other) // 返回值为Any& 以支持连续交换
//     {
//         std::swap(_content, other._content);
//         return *this;
//     }

// public:
//     // 默认构造
//     Any() : _content(nullptr) {}
//     // 为构造加上模版以支持任何数据类型来初始化
//     template <typename T>
//     Any(const T &val) : _content(new placeholder<T>(val))
//     {
//     }
//     // 拷贝构造函数
//     Any(const Any &other)
//     {
//         // 构造这个值的对象
//         // 判断有没有值
//         if (other._content == nullptr)
//         {
//             _content = nullptr;
//             return;
//         }
//         _content = other._content->clone();
//     }
//     // 赋值重载，也实现为两个版本
//     Any &operator=(Any other) // 使用现代方法，让形参进行拷贝构造
//     {
//         Swap(other);
//         return *this;
//     }
//     // 模版的赋值重载
//     template <typename T>
//     Any &operator=(const T &val)
//     {
//         // 利用构造创建一个临时对象然后Swap
//         Any(val).Swap(*this);
//         return *this;
//     }

//     // 获取存储的数据内容，需要写成模版，因为可以存储不同类型的数据
//     template <class T>
//     T *get()
//     {
//         // 确保获取的数据类型与存储的数据类型一致
//         assert(typeid(T) == _content->type());
//         return &((placeholder<T> *)_content)->_val;
//     }

//     ~Any()
//     {
//         // 释放资源,有资源就释放
//         if (_content != nullptr)
//         {
//             delete _content;
//         }
//     }
// };

// class Test
// {
// public:
//     Test() { std::cout << "构造" << std::endl; }
//     Test(const Test &t) { std::cout << "拷贝构造" << std::endl; }
//     ~Test() { std::cout << "析构" << std::endl; }
// };

// int main()
// {
//     // Test t;
//     // {
//     //     Any a;
//     //     a = t;
//     // }
//     // Any a;
//     // a = 10;
//     // int * p1 = a.get<int>();
//     // std::cout << *p1 << std::endl;

//     //c++17当中 any 类的使用
//     std::any a;
//     a = 10;
//     int* p1 = std::any_cast<int>(&a);
//     std::cout << *p1 << std::endl;

//     return 0;
// }

// 日志模块，此处简单实现，利用函数 fprintf loacltime strftime
//  struct tm *localtime(const time_t *timep);
// 加入日志等级
#define INF 0
#define DBG 1
#define ERR 2
#define LOG_LEVEL DBG // 可以用这个来控制日志的打印
#define LOG(level, format, ...)                                                             \
    do                                                                                      \
    {                                                                                       \
        if (level < LOG_LEVEL)                                                              \
            break;                                                                          \
        time_t t = time(nullptr);                                                           \
        struct tm *ltm = localtime(&t);                                                     \
        char tmp[32] = {0};                                                                 \
        strftime(tmp, 31, "%H:%M:%S", ltm);                                                 \
        fprintf(stdout, "[%p %s %s:%d] " format "\n",(void*)pthread_self(), tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
    } while (0);

#define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
#define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)


// 缓冲区Buffer 模块的实现
// Buffer 的功能，为每一条连接均提供缓冲区；默认空间大小，读位置、写位置，使用vector<char> 来实现，不适用string 因为在字符串中遇见\0 便会停止处理
// 写入数据，首先需要保证空间足够，后沿空间足够就直接写入，倘若后沿空间不够而前沿空间足够就将数据整体向前移动然后再写入数据，如果均不够就扩容；
// 拿数据，需要保证所要拿的数据大于等于能拿的数据；
// 将拿数据的过程与移动指针的过程拆分为各个函数，然后再利用另外的函数进行封装
#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
private:
    std::vector<char> _buffer;
    uint64_t _write_idx; // 写位置偏移量
    uint64_t _read_idx;  // 读位置偏移量
private:
    char *Begin()
    {
        return &*_buffer.begin();
    }

public:
    Buffer() : _buffer(BUFFER_DEFAULT_SIZE), _write_idx(0), _read_idx(0)
    {
    }
    ~Buffer() {}
    // 获取写位置
    char *WritePostion() { return Begin() + _write_idx; }
    char *ReadPostion() { return Begin() + _read_idx; }
    // 获取缓冲区当中前沿、后沿的空间大小
    uint64_t TailIdleSize() { return _buffer.size() - _write_idx; }
    uint64_t HeadIdelSize() { return _read_idx; }
    // 获取可读数据的大小
    uint64_t ReadAbleSize() { return _write_idx - _read_idx; }
    // 将读、写偏移移动
    void MoveWriteOffset(uint64_t len)
    {
        // 不能超过总空间
        assert(_write_idx + len <= _buffer.size());
        // assert(len <= TailIdleSize());
        _write_idx += len;
    }
    void MoveReadOffset(uint64_t len)
    {
        // len 一定小于可读的数据长度
        assert(len <= ReadAbleSize());
        _read_idx += len;
    }
    // 确保写的空间足够，不够就进行调整，三种情况
    void EnsureWriteSpace(uint64_t len)
    {
        if (len <= TailIdleSize())
            return;
        else if (len <= HeadIdelSize() + TailIdleSize())
        {
            // 将数据向前挪动，利用函数copy
            uint64_t strlen = ReadAbleSize();
            //             template< class InputIt, class OutputIt >
            // OutputIt copy( InputIt first, InputIt last, OutputIt d_first );
            std::copy(ReadPostion(), ReadPostion() + strlen, Begin());
            // 处理指针
            _write_idx = strlen;
            _read_idx = 0;
        }
        else
        {
            // 空间不够进行扩容，使用vector resize()进行扩容
            _buffer.resize(_write_idx + len);
        }
    }

    // 写入数据、读取数据
    void Write(const void *data, uint64_t len)
    {
        if (len <= 0)
            return;
        // 确保空间足够
        EnsureWriteSpace(len);
        // 到了此处空间一定足够，插入数据
        // 由于void* 类型的数据没有步长，此处需要强转
        const char *str = (const char *)data;
        // DBG_LOG("buffer 写入数据:%s ", str);
        // 使用copy 进行插入
        std::copy(str, str + len, WritePostion());
    }
    void Read(const void *buf, uint64_t len)
    {
        // 所要读取的数据一定小于等于可读数据
        assert(len <= ReadAbleSize());
        // 利用copy
        std::copy(ReadPostion(), ReadPostion() + len, (char *)buf);
    }
    // 读、写之后+处理指针
    void WriteAndPush(const void *data, uint64_t len)
    {
        Write(data, len);
        MoveWriteOffset(len);
    }
    void ReadAndPop(const void *buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }

    // 读、写以字符串的形式
    void WriteString(const std::string &data)
    {
        uint64_t len = data.size();
        if (len == 0)
            return;
        // 服用Write
        Write((void *)data.c_str(), len);
    }
    std::string ReadAsString(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len);
        return str;
    }
    // 读、写+移动指针
    void WriteStringAndPush(const std::string &data)
    {
        WriteString(data.c_str());
        MoveWriteOffset(data.size());
    }
    std::string ReadAsStringAndPop(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string ret = ReadAsString(len);
        MoveReadOffset(len);
        return ret;
    }
    // write Buffer 当中的数据
    void WriteBuffer(Buffer &data)
    {
        Write(data.ReadPostion(), data.ReadAbleSize());
    }
    // 写并移动指针
    void WriteBufferAndPush(Buffer &data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAbleSize());
    }

    // 获取一行的数据、获取一行的结尾、获取一行的数据并且移动指针
    char *FindCRLF()
    {
        // memchr：void* memchr(void* ptr, int value, size_t num); 在ptr 当中查找value,所查找的区间大小为num
        // memchr 的返回值，找到了会返回地址，没有找到返回nullptr
        char *res = (char *)memchr(ReadPostion(), '\n', ReadAbleSize());
        return res;
    }
    std::string GetLine()
    {
        char *pos = FindCRLF();
        if (pos == nullptr)
            return "";
        // 找到了利用ReadAsString 进行提取,将\n 一起提取出来
        return ReadAsString(pos - ReadPostion() + 1);
    }
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }

    // 清理缓冲区
    void Clear()
    {
        _read_idx = 0;
        _write_idx = 0;
    }
};

// 测试
// int main()
// {
//     Buffer buf;
//     std::string str = "hello world";
//     // 写入
//     // buf.WriteStringAndPush(str);
//     // Buffer buf1;
//     // buf1.WriteBufferAndPush(buf);

//     // std::cout << buf.ReadAsStringAndPop(str.size()) << std::endl;
//     // std::cout << buf.ReadAbleSize() << std::endl;
//     // std::cout << buf1.ReadAbleSize() << std::endl;
//     //测试扩容部分，大于1024
//     for(int i =0; i< 200;i++)
//     {
//         std::string s = str+std::to_string(i) + '\n';
//         buf.WriteStringAndPush(s);
//     }
//     while(buf.ReadAbleSize() > 0)
//     {
//         std::string line = buf.GetLineAndPop();
//         // std::cout << line ;
//         // LOG("%s" , line.c_str());
//         // LOG("hello");//可变参数部分带上##，此处可以省略可变参数
//         INF_LOG("%s" , line.c_str());
//     }

//     return 0;
// }

// Socket模块，对socket 套接字进行管理, bind connect accept recv send close
// 进一步封装，创建监听套接字、普通套接字；设置套接字选项--开启端口重用，这个选项是因为：
// 当一连接绑定了地址与端口号之后，一旦主动断开连接这个连接最终俊辉处于timewait 保护状态，此时套接字无法立即被释放，因此其ip与port依旧被占用
//  无法立即使用，在服务器当中，这样做当服务器挂掉了就不能立即重新启动，所以需要设置为地址端口重用；另外就是设置为非阻塞状态
#define MAX_LISTEN 1024
class Socket
{
private:
    int _sockfd;

public:
    Socket() {}
    Socket(int sockfd) : _sockfd(sockfd)
    {
    }
    ~Socket() {}

    // 获取文件描述符
    int fd() { return _sockfd; }
    // 创建套接字
    bool Create()
    {
        // 使用socket创建套接字信息
        //  int socket(int domain, int type, int protocol);
        _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (_sockfd < 0)
        {
            ERR_LOG("create sockfd error");
            return false;
        }
        int sockfd = _sockfd;
        INF_LOG("create socket success : %d ", sockfd);
        return true;
    }
    // 绑定ip地址与端口号 bind
    bool Bind(uint16_t port, const std::string &ip)
    {
        // DBG_LOG("进入Bind函数:%d , %s", (int)port, ip.c_str());
        // 使用Bind 将套接字与ip port 进行绑定
        //    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//成功返回0失败返回-1
        // 首先需要创建struct sockaddr_in，将ip 和 port 放进这个结构体变量中作为bind 的参数
        struct sockaddr_in addr;
        addr.sin_family = AF_INET; // 协议族AF_INET表示使用ipv4进行通信
        // int inet_pton(int af, const char *restrict src, void *restrict dst); inet_addr 并不是线程安全的，因为inet_addr 将地址信息存放在静态空间当中
        // inet_pton(AF_INET, ip.c_str(), &(addr.sin_addr.s_addr));
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        addr.sin_port = htons(port); // 将主机序列转换为网络序列
        // 因为不同计算机在定义变量存储数据的时候，会有大端小端的概念，而网络中规定为大端传输（大端：高权职位位于低地址处），所以将数据从主机发送到网络需要统一处理
        socklen_t len = sizeof(struct sockaddr_in);
        // 判断bind 执行后的返回值
        int ret = bind(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            ERR_LOG("bind error: %d ", ret);
            return false;
        }
        INF_LOG("socket bind success");
        return true;
    }
    // 开始监听 --> Listen
    bool Listen(int backlog = MAX_LISTEN)
    {
        // int listen(int sockfd, int backlog); 成功返回0失败返回-1
        int ret = listen(_sockfd, backlog);
        if (ret < 0)
        {
            ERR_LOG("listen error");
            return false;
        }
        INF_LOG("socket listen success");
        return true;
    }
    // 向服务器发起连接请求
    bool Connect(uint16_t port, const std::string &ip)
    {
        // int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 成功返回0失败返回-1
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &(addr.sin_addr.s_addr));
        addr.sin_port = htons(port);
        socklen_t len = sizeof(struct sockaddr);
        int ret = connect(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            ERR_LOG("conect error");
            return false;
        }
        INF_LOG("socket connect success");
        return true;
    }
    // 获取新连接
    // 服务端接受客户端的请求，需要得知客户端的需求，并且得到套接字;所以Accept 需要返回新获得的套接字
    int Accept()
    {
        // int accept(int sockfd, struct sockaddr *_Nullable restrict addr, socklen_t *_Nullable restrict addrlen);
        // 此处拿客户的addr 没什么用，所以此处不获取
        int newfd = accept(_sockfd, nullptr, nullptr);
        if (newfd < 0)
        {
            ERR_LOG("socket accept failed");
            return -1;
        }
        return newfd;
    }
    // 接受数据
    ssize_t Recv(void *buf, size_t n, int flag = 0)
    {
        // 直接调用recv 向套接字当中写入数据
        ssize_t ret = recv(_sockfd, buf, n, flag);
        // 判断返回值小于0的情况，由于此处处理为非阻塞读，当返回值小于0不一定是读错误，需要根据错误码分情况讨论
        if (ret <= 0) // 返回值为0表示对端将连接关闭
        {
            // 没有数据可以读、信号中断
            if (errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            // 此时才是真正的读错误
            ERR_LOG("socket recv error，ret: %ld" , ret);
            return -1;
        }
        // DBG_LOG("接受到数据:%s" , (char*)buf);
        return ret; // 返回数据读取到的个数，交给上层去处理
    }
    // 发送数据
    ssize_t Send(const void *buf, size_t len, int flag = 0)
    {
        // ssize_t send(int sockfd, const void buf[.len], size_t len, int flags);
        ssize_t ret = send(_sockfd, buf, len, flag);
        if (ret < 0)
        {
            if (errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            // 真正的错误
            return -1;
        }
        // DBG_LOG("发送数据: %ld , %s", ret , (char*)buf);
        return ret;
    }
    // 封装，创建监听套接字、普通套接字
    // 服务器端一般不绑定固定的ip地址,使用 0.0.0.0 随机地址就可以了
    bool CreateServer(uint16_t port, const std::string &ip = "0.0.0.0", bool block_flag = false)
    {
        // 创建套接字、bind、listen，将套接字设置为非阻塞状态
        if (Create() == false)
            return false;
        if (block_flag)
            NonBlock();
        if (Bind(port, ip) == false)
            return false;
        if (Listen() == false)
            return false;
        // 设置套接字为重用地址
        ReuseAddress();
        return true;
    }
    bool CreateClient(uint16_t port, const std::string &ip) // 客户端的ip port
    {
        // 客户端的地址port 由OS自动绑定
        if (Create() == false)
            return false;
        if (Connect(port, ip) == false)
            return false;
        return true;
    }
    // 设置套接字选项,利用setsockopt
    void ReuseAddress()
    {
        // int setsockopt(int sockfd, int level, int optname,const void optval[.optlen],socklen_t optlen);
        // setsockopt 设置套接字选项，第二个参数表示选项级别，此处为套接字，使用SOL_SOCKET ， 第三个参数表示具体选项名称，此处需要重用地址
        // 所以填写SO_REUSEADDR ； 第四个参数表示指向包含新选项的缓冲区指针，最后一个参数为该缓冲区的大小
        int val = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(val));
        val = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(val));
    }
    // 将套接字设置为非阻塞状态
    void NonBlock()
    {
        // 利用fcntl : file contrl
        int flag = fcntl(_sockfd, F_GETFL);
        if (flag < 0)
        {
            ERR_LOG("sockfd fcntl error");
            return;
        }
        // 将非阻塞属性设置进socket 当中
        fcntl(_sockfd, F_SETFL, (flag | O_NONBLOCK));
    }

    // 关闭套接字
    void Close()
    {
        if (_sockfd != -1)
        {
            close(_sockfd);
            _sockfd = -1;
        }
    }

    // 非阻塞读与非阻塞写
    ssize_t NonBlockRecv(void *buf, size_t len)
    {
        return Recv(buf, len, MSG_DONTWAIT);
    }
    ssize_t NonBlockSend(const void *buf, size_t len)
    {
        return Send(buf, len, MSG_DONTWAIT);
    }
};

class Poller; // 将Channel 模块与 Poller 模块做整合
// 修改，EventLoop中包含了Poller ,是对Channel、Poller 的进一步封装，此处在Channel 当中带EventLoopD对象
class EventLoop;

// Channel 对一个描述符的监控事件管理,以及事件就绪了该如何去处理
// 需要对于读、写、错误、连接关闭、事件就绪均要调用的函数，设置回调方法；
// 以及维护当前文件描述符、该文件描述符所要关系的事件、就绪的事件
class Channel
{
private:
    int _fd;
    // Poller* _poller;
    EventLoop *_loop;
    uint32_t _events;
    uint32_t _revents;
    using EventCallback = std::function<void()>;
    // 五个回调函数
    EventCallback _read_callback;
    EventCallback _write_callback;
    EventCallback _error_callback;
    EventCallback _close_callback;
    EventCallback _event_callback;

public:
    // 构造与析构
    // Channel(Poller* poller, int fd = -1) : _fd(fd), _poller(poller), _events(0), _revents(0)
    Channel(EventLoop *loop, int fd = -1) : _fd(fd), _loop(loop), _events(0), _revents(0)
    {
    }
    // 获取文件描述符
    int Fd() { return _fd; }
    // 获取关心的事件
    uint32_t Events() { return _events; }
    ~Channel() {}
    void SetRevent(uint32_t revents) { _revents = revents; }
    // 五个回调函数的设置函数
    void SetReadCallback(const EventCallback &cb) { _read_callback = cb; }
    void SetWriteCallback(const EventCallback &cb) { _write_callback = cb; }
    void SetErrorCallback(const EventCallback &cb) { _error_callback = cb; }
    void SetCloseCallback(const EventCallback &cb) { _close_callback = cb; }
    void SetEventCallback(const EventCallback &cb) { _event_callback = cb; }
    // 判断当前是否关心这个fd 的读、写事件
    bool ReadAble()
    {
        return (_events & EPOLLIN); //& 有0则为0，全1才为1
    }
    bool WriteAble()
    {
        return (_events & EPOLLOUT);
    }
    // 启动、关闭读写事件的关心（监控）
    void EnableRead()
    {
        _events |= EPOLLIN;
        // 更新进epoller内核
        Update();
    }
    void EnableWrite()
    {
        _events |= EPOLLOUT;
        // 更新进epoller内核
        Update();
        // DBG_LOG("epoll enablewrite...")
    }
    void DisableRed()
    {
        _events &= (~EPOLLIN); //| 有1 则为1，全0才为0; &: 有0则为0，全1则为1
                               // 更新进epoller内核
        Update();
    }
    void DisableWrite()
    {
        _events &= (~EPOLLOUT);
        // 更新进epoller内核
        Update();
    }
    // 关闭所有事件的关心，将所有位置为0
    void DisableAll()
    {
        _events = 0;
        // 更新进epoller内核
        Update();
    }
    // 移除关心(监控)
    void Remove();
    void Update();
    // 派发任务，有事件就绪了，这个socket 该去调用什么函数去处理任务
    void HandleEvent()
    {
        // 判断fd 的事件哪些就绪了去调用对应的函数就可以了；
        if ((_revents & EPOLLIN) || (_revents & EPOLLHUP) || (_revents & EPOLLPRI))
        {
            // 每一个事件就绪均会调用的函数
            if (_event_callback)
                _event_callback();
            if (_read_callback)
                _read_callback();
        }
        // 根据就绪的事件来派发任务,但是由于在数据写入的时候发现连接断开，写入出错，那么就要关闭连接，释放……而又要处理其错误，但是连接又释放了
        // 此时再去根据套接字处理，就会报错，故而此处采用id else if …… 而不是 if
        if (_revents & EPOLLOUT)
        {
            if (_write_callback)
                _write_callback();
        }
        else if (_revents & EPOLLERR)
        {
            if (_error_callback)
                _error_callback();
        }
        else if (_revents & EPOLLHUP)
        {
            if (_close_callback)
                _close_callback();
        }
    }
};

// Poller模块，对任意fd 进行io事件监控；是对于epoller 的封装，将fd 关心的事件设置进epoll 内核当中，提供相应的接口函数
// 需要利用哈希表来保存fd  与Channel* 的映射关系，方便派发任务；还需要用struct epoll_event 数据保存就绪的事件
// 成员变量：epoll模型、struct epoll_event 数组、哈希表
#define MAX_EPOLLEVENTS 1024
class Poller
{
private:
    int _epfd;
    struct epoll_event _evs[MAX_EPOLLEVENTS];
    std::unordered_map<int, Channel *> _channels;

private:
    // 对epoll 直接的操作
    void Update(Channel *channel, int op)
    {
        // 调用 epoll_ctl 实现
        //  int epoll_ctl(int epfd, int op, int fd, struct epoll_event *_Nullable event);
        // 获取文件描述符
        int fd = channel->Fd();
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = channel->Events();
        // 调用epoll_ctl
        int ret = epoll_ctl(_epfd, op, fd, &ev);
        if (ret < 0)
        {
            ERR_LOG("epoll_ctl error");
        }
          INF_LOG("epoll_ctl success");
    }
    // 判断一个channel 是否已经添加进epoll 当中 --> 在哈希表中进行查找便可
    bool HasChannel(Channel *channel)
    {
        auto it = _channels.find(channel->Fd());
        if (it == _channels.end())
        {
            return false;
        }
        return true;
    }

public:
    // 构造、析构
    Poller()
    {
        // 在构造的时候调用epoll_create 创建epoll 模型
        _epfd = epoll_create(MAX_EPOLLEVENTS);
        if (_epfd < 0)
        {
            ERR_LOG("epoll create error");
            abort(); // 直接退出程序
        }
    }
    // 添加或者修改关心的事件
    void UpdateEvent(Channel *channel)
    {
        // 调用Update，先判断_channels 当中有没有这个fd, 没有的话，需要先插入，然后再设置关心事件
        if (HasChannel(channel) == false)
        {
            _channels.insert(std::make_pair(channel->Fd(), channel));
             Update(channel, EPOLL_CTL_ADD); // 将事件添加进epoll当中
        }
        Update(channel, EPOLL_CTL_MOD); // 将事件添加进epoll当中
    }
    // 移除关心
    void RemoveEvent(Channel *channel) // EPOLL_CTL_DEL
    {
        // 先将事件从_channels当中删除,然后再 从epoll 当中移除，
        // 先判断有没有这个fd
        auto it = _channels.find(channel->Fd());
        if (it == _channels.end())
            return;
        _channels.erase(it);
        Update(channel, EPOLL_CTL_DEL);
    }
    // 开始关心，并返回活跃的连接
    void Poll(std::vector<Channel *> *active) // 参数为输出型参数
    {
        // 利用epoll_wait
        int nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1); // 阻塞监控
        if (nfds < 0)
        {
            // 说明没有事件就绪，但是需要分情况讨论
            if (errno == EINTR)
                return;
            ERR_LOG("epoll_wait error");
            abort();
        }
        // 获得了就绪的事件,调用Channel 当中的HandeEvent 方法
        for (int i = 0; i < nfds; i++)
        {
            auto it = _channels.find(_evs[i].data.fd); // 获取就绪事件
            assert(it != _channels.end());
            // 将就绪的事件设置进Channel当中
            it->second->SetRevent(_evs[i].events);
            // 并将就绪的事件放入数组当中
            active->push_back(it->second);
        }
    }
    ~Poller()
    {
    }
};

// 将任务封装成定时任务
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    // 任务id、定时时间、当前任务是否被取消了的状态标志位、所要执行什么任务、删除在时间轮当前任务的信息的函数
    uint64_t _id;
    uint32_t _timeout;
    bool _canceled;
    TaskFunc _task_cb;
    ReleaseFunc _release;

public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &cb)
        : _id(id), _timeout(delay), _task_cb(cb),_canceled(false)//忘记初始化_cancleed为false！！！调试了许久
    {
    }
    ~TimerTask()
    {
        // 时间轮借助于对象生命周期结束自动调用析构函数的特点从而体现为自动调用函数，此处只有没有取消任务才会执行任务
        if (_canceled == false)
            _task_cb();
        // 将当前任务从时间轮当中移除
        DBG_LOG("销毁定时任务");
        _release();
    }
    // 向外提供设置是否取消任务、设置将任务从时间轮当中移除、获取过期事件的接口函数
    void Cancel()
    {
        DBG_LOG("取消定时任务成功");
        _canceled = true;
    }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
    uint32_t DelayTime() { return _timeout; }
};

// TimeWheel模块，将之前所写的时间轮与timerfd 相结合;timerfd 设置为每秒钟触发一次定时事件，当事件触发的时候，则运行一次timerwheel 的runtimertask
// 执行一下所有的过期定时任务
class TimerWheel
{
private:
    using PtrTask = std::shared_ptr<TimerTask>; // 指向定制任务的指针,shared_ptr
    using WeakTask = std::weak_ptr<TimerTask>;
    int _tick;     // 定时的秒针，走到哪里就执行哪里的任务
    int _capacity; // 时间轮中的可以设置的过期时间
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers; // 管理定时任务与id 的映射关系
    // 人物使用weak_ptr 来指向，weak_ptr 并不会占用shared_ptr 的引用计数，借助于weak_ptr 使得多个shread_ptr 可以指向同一个资源
    // 当在_wheel中没有shared_ptr 中指向该任务，就会自动调用析构函数

    // 将时间轮与EventLoop对象结合
    EventLoop *_loop;                        // 需要将对timerfd 事件的监控借助于_loop放入epoll模型当中
    int _timerfd;                            // 定时器，使用timerfd
    std::unique_ptr<Channel> _timer_channel; // Channel 是对连接的管理,此处_timer_channel用来专门对_timerfd 进行管理
private:
    // 将定时事件从时间轮当中移除
    void RemoveTimer(uint64_t id)
    {
        // 利用id，在_timers找到对应的定时任务
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        // 找到了就将这个定时任务从_timers 当中移除
        _timers.erase(it);
        DBG_LOG("id: %ld , 从时间轮当中移除" , id);
    }
    // 创建timerfd
    static int CreateTimerfd() // 定义为静态成员变量就无需传递this 指针，传参更加方便
    {
        // 调用timerfd_create 创建、判断返回值
        //  #include <sys/timerfd.h> int timerfd_create(int clockid, int flags);
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            ERR_LOG("timerfd create error");
            abort();
        }
        INF_LOG("timerfd create success");
        // 设置timerfd 的通知时间；利用函数timerfd_settime
        //  int timerfd_settime(int fd, int flags,const struct itimerspec *new_value,struct itimerspec *_Nullable old_value);
        struct itimerspec itime;
        // 设置第一次超时的时间以及第一次过后的超时时间
        itime.it_value.tv_sec = 1;    // 第一次超时时间为1s
        itime.it_value.tv_nsec = 0;   // 避免随机值
        itime.it_interval.tv_sec = 1; // 第一次超时后每一次的时间间隔
        itime.it_interval.tv_nsec = 0;
        // 设置进内核
        timerfd_settime(timerfd, 0, &itime, nullptr);
        INF_LOG("timerfd set success");
        return timerfd;
    }
    // 读取当前超时次数
    int ReadTimerfd()
    {
        // 直接使用read,timerfd 当中存放的是八字节的数据
        uint64_t times = 0;
        ssize_t n = read(_timerfd, &times, 8);
        if (n < 0)
        {
            ERR_LOG("timerfd read error");
            abort();
        }
        INF_LOG("timerfd read success");
        return times;
    }
    // —_tick 根据过去的描述进行移动,执行当前_tick所执行的所有定时任务
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        INF_LOG("时间轮中指针向后走了一步");
        // 定时任务的执行依靠于其析构函数的调用，所以此处仅需要释放_tick指向_wheel中的数据
        _wheel[_tick].clear();
    }
    // 根据当前超时次数,就是过了多少秒-->ReadTimerfd() ，执行_tick其所对应的任务 --> RunTimerTask()
    void OnTime() // 读取timerfd 当中的数据 + 执行时间轮当中_tick 所对应的定时任务
    {
        int times = ReadTimerfd();
        for (int i = 0; i < times; i++)
        {
            RunTimerTask();
        }
    }
    // 添加定时任务 --> 将传进来的任务根据id、delay封装为定时任务-->TimerTask --> 放入时间轮当中、_timers当中（记录任务与id 的映射关系）
    void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        PtrTask pt(new TimerTask(id, delay, cb));
        // 设置定时任务当中的回调函数,此处为非活跃连接管理，所以传入销毁连接的函数
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        // 获取当前应该放在时间轮的那个位置上
        int pos = (_tick + delay) % _capacity;
        // 插入
        _wheel[pos].push_back(pt);
        // 放入_timers当中
        _timers.insert(std::make_pair(id, WeakTask(pt)));
        DBG_LOG("timerwheel add success");
    }
    // 刷新（延迟）定时任务-->本质就是多创建一个shread_ptr指针指向任务，引用计数不为0就不会调用析构函数
    void TimerFlushInLoop(uint64_t id)
    {
        // 获取任务
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        // 设置shared_ptr
        PtrTask pt = it->second.lock(); // lock可以获取weak_ptr 管理对象所对应的shared_ptr
        // h获取超时时间
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        // 将pt插入时间轮当中
        _wheel[pos].push_back(pt);
    }
    // 取消定时任务
    void TimerCancelInLoop(uint64_t id)
    {
        // 设置TimerTask _cancled标志位
        // 先利用id 在——times 中找到对应的任务指针
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        PtrTask pt = it->second.lock();//这个时候weak_ptr 当中的任务可能已经失效了
        if(pt) pt->Cancel();//
    }

public:
    TimerWheel(EventLoop *loop)
        : _loop(loop), _tick(0), _capacity(60), _wheel(_capacity), _timerfd(CreateTimerfd()), _timer_channel(new Channel(_loop, _timerfd))
    {
        // 初始化Channel对象，Channel 当中保存了所关心的socket、其所关心的事件、就绪的事件、epoll模型(Poller 指针),五个回调函数
        // 对于此处的timerfd 来说，timerfd中到来了数据就取时间轮当中执行_tick所指向的定时任务
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime, this));
        _timer_channel->EnableRead(); // 关心其读事件
    }
    // 向上层提供的接口函数
    // 因为定时器当中有一个_timers， 可能会多个线程同时操作而存在线程安全问题，因此要么加锁处理，要么借助与EventLoop当中的RunInLoop来处理
    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb);
    // 刷新（延迟）定时任务
    void TimerFlush(uint64_t id);
    // 取消定时任务
    void TimerCancel(uint64_t id);
    // 判定当前定时任务是否存在，这个函数不能再外部使用，只在模块中eventloop对应的线程当中执行
    bool HasTimer(uint64_t id)
    {
        // 其实就是在哈希表中利用id 进行查找
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return false;
        }
        return true;
    }
    ~TimerWheel() {}
};

//通用类型Any的实现
//利用多态 + 模版
class Any
{
private:
    class holder
    {
    public:
        virtual ~holder(){}//派生类可选是否重写
        //获取存储的数据类型、拷贝构造clone
        virtual const std::type_info& type() = 0;//纯虚函数，派生类必须进行重写
        virtual holder* clone() = 0;
    };
    template<typename T>
    class placeholder : public holder
    {
    private:
        T _val;//存储数据
    public:
        //重写父类的虚函数
        placeholder(const T& val):_val(val){}
        //重写基类的虚函数,加上virtual 可以更加明确地知道这个函数是重写的虚函数
        virtual const std::type_info type()
        {
            return typeid(T);
        }
        virtual holder* clone()
        {
            return new placeholder(_val);
        }
    };
    holder* _content;//基类指针
public:
    //构造
    //拷贝构造，本类型数据、任意类型数据（模版）
    //赋值重载函数,本类型数据、任意类型数据（模版）
    //get 获取存储数据的指针
    //析构函数
    Any():_content(nullptr){}
    Any(const Any& val)
    {
        //根据content中保存的数据进行构造
        if(val._content==nullptr) return;
        _content = val._content->clone();
    }

    template<class T>
    Any(const T& val)
    {
        _content = new placeholder<T>(val);
    }

    Any& Swap(Any& val)
    {
        std::swap(_content , val._content);
        return *this;
    }
    //赋值重载函数
    Any& operator=(const Any& val)//利用现代写法
    {
       Any(val).Swap(*this);
        return *this;
    }
    
    template<class T>
    Any& operator=(const T& val)
    {
        Any(val).Swap(*this);
        return *this;
    }
    //get函数,返回具体存储数据的指针
    template<class T>
    T* get()
    {
        assert(typeid(T)==_content->type());
        return &((placeholder<T>*)_content)->_val;
    }
};

// //Channel 中的Remove Update 函数需要在Poller 类下实现，实则就是调用Poller中的RemoveEvent 以及 UpdateEvent
// void Channel::Remove() {return _poller->RemoveEvent(this);}
// void Channel::Update() {return _poller->UpdateEvent(this);}

// EventLoop模块，Poller模块为EventLoop模块的一个子模块，对事件进行管理
// eventfd 创建一个文件描述符用于事件通知；需要注意的是信号是针对进程进行事件通知的，而eventfd 的本质是内核管理的计数器，这一点与信号量不同
// 从eventfd 中取一次数据就会清零，而该文件中OS会记录超时的次数
//  int eventfd(unsigned int initval, int flags);
// 第一个参数表示计数器初始值，第二个参数主要有EFD_COLEXEC 表示禁止进程复制（fork,子进程会继承父进程的文件描述符）
// EFD_NONBLOCK 启动非阻塞属性；返回值为文件描述符;需要注意的是eventfd也是通过write read 进行操作的，读取、写入的数据为8byte
// 为了保证线程安全，需要将一个连接的所有操作均在eventloop 所对应的线程当中执行；解决方案：当前操作就处于eventloop所对应的线程当中，直接
// 执行便可，如果不再就将任务进行封装，放入任务队列当中；需要对此任务队列进行加锁操作
// 而又因为等待IO事件就绪而导致执行流程阻塞，这时候任务队列当中的任务得不到执行，此时就需要利用eventfd 来进行事件通知，来唤醒事件监控的阻塞
class EventLoop // 将Channel对象管理起来，并且带有Poller 并且与线程一一对应；上层直接使用EventLoop
{
private:
    using Functor = std::function<void()>;
    // epoll模型 --> 事件通知
    std::thread::id _thread_id; // 线程id
    int _event_fd;              // 利用eventfd进行通知，避免epoll的阻塞
    // eventfd 也是文件描述符，可以利用Channel智能指针进行统一的管理
    std::unique_ptr<Channel> _event_channel;
    Poller _poller;              // 对所有的描述符事件进行监控
    std::vector<Functor> _tasks; // 任务池
    // 加锁，以保证扔任务池的线程安全问题
    std::mutex _mutex;
    // 时间轮
    TimerWheel _timer_wheel;

public:
    // 执行任务池当中的所有任务
    void RunAllTask()
    {
        // 将任务队列当中的任务交换出来，然后再处理，需要加锁，加锁的过程可以利用unique_lock
        std::vector<Functor> functor;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(functor);
        }

        // 遍历任务数组执行任务
        for (auto &f : functor)
        {
            f();
        }
        return;
    }

    // 创建eventfd
    static int CreateEventfd()
    {
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ERR_LOG("create eventfd error");
            abort(); // 结束进程
        }
         INF_LOG("create eventfd success");
        return efd;
    }
    // eventfd 的读回调函数
    void ReadEventfd()
    {
        uint64_t res = 0; // eventfd 读写8字节数据
        int ret = read(_event_fd, &res, 8);
        if (ret < 0)
        {
            // 由于是非阻塞读，需要对返回值为-1的情况分情况讨论
            if (errno == EAGAIN || errno == EINTR)
            {
                return;
            }
            // 真正的读错误
            ERR_LOG("eventfd read error");
            abort();
        }
        INF_LOG("eventfd read success");
        return;
    }

    void WeakUpEventFd()
    {
        uint64_t val = 1;
        int ret = write(_event_fd, &val, 8);
        if (ret < 0)
        {
            // 由于是非阻塞，当返回值小于-1需要分情况讨论
            if (errno == EAGAIN || errno == EINTR)
            {
                return;
            }
            // 真正的写错误
            ERR_LOG("evenfd write error");
            abort();
        }
    }

public:
    //_thread_id 直接调用函数this_thread::get_id()获取，对于_event_fd 需要调用函数eventfd ，封装一下初始化；_event_channl 使用new
    EventLoop()
        : _thread_id(std::this_thread::get_id()), _event_fd(CreateEventfd()), _event_channel(new Channel(this, _event_fd)), _timer_wheel(this)
    {
        // 由于Eventfd 由Channel 进行了管理，需要设置其回调函数,其读事件就是读取eventfd 当中的数据
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd, this)); // 类成员函数使用Bind 需要加上&
        // 开辟对_event_fd 的读监控
        _event_channel->EnableRead();
    }
    ~EventLoop() {}
    // 如果任务不再当前eventloop所对应的线程当中，就将任务封装一下放入任务池当中
    void RunInLoop(const Functor &cb)
    {
        // 统一执行任务的接口，其中再分情况讨论
        if (IsInLoop())
        {
            return cb(); // 直接执行任务
        }
        QueueInLoop(cb); // 将任务放入任务队列当中
    }

    // 将任务放入任务队列当中
    void QueueInLoop(const Functor &cb)
    {
        {
            // 访问临界资源需要加锁
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.push_back(cb);
        }
        // 向eventfd 中写入，避免epoll模型因为没有IO事件而阻塞
        WeakUpEventFd();
    }
    bool IsInLoop() // 判断当前是否处于eventloop所对应的线程当中
    {
        // 比较eventloop当中存储的线程id 与获取当前线程id进行比较便可
        return (_thread_id == std::this_thread::get_id());
    }
    // 检查当前执行任务是在eventloop所对应的线程当中
    void AssertInLoop()
    {
        assert(_thread_id == std::this_thread::get_id());
    }
    // eventloop是对事件的更一步管理，关心这些事件需要关系哪些，所以需要提供与epoll模型相关的接口
    void UpdateEvent(Channel *channel) // Poller 当中有同名的接口函数,将_event_fd 写入epoll模型当中
    {
        _poller.UpdateEvent(channel);
    }
    void RemoveEvent(Channel *channel)
    {
        _poller.RemoveEvent(channel);
    }
    // 事件关心、就绪事件处理、执行任务;Eventloop的核心工作
    void Start()
    {
        while (1)
        {
            // 检测哪些事件就绪了
            std::vector<Channel *> actives;
            _poller.Poll(&actives);
            // 处理就绪事件
            for (auto &channel : actives)
            {
                // DBG_LOG("fd:%d 活跃" , channel->Fd());
                // 直接交给RunInLoop来处理，判断任务是否处于当前eventLoop线程下
                channel->HandleEvent(); // 派发任务
            }
            // 执行任务
            RunAllTask();
        }
    }

    // 定时任务，增加、刷新、取消
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        return _timer_wheel.TimerAdd(id, delay, cb);
    }
    void TimerFlush(uint64_t id)
    {
        return _timer_wheel.TimerFlush(id);
    }
    void TimerCancle(uint64_t id)
    {
        return _timer_wheel.TimerCancel(id);
    }
    // 判断某个定时任务是否存在
    bool HasTimer(uint64_t id)
    {
        return _timer_wheel.HasTimer(id);
    }
};

// Channel 中的Remove Update 函数需要在EventLoop 类下实现，实则就是调用EventLoop中的RemoveEvent 以及 UpdateEvent
// 本质上还是调用Poller当中的RemoveEvent 以及 UpdateEvent
void Channel::Remove() { return _loop->RemoveEvent(this); }
void Channel::Update() { return _loop->UpdateEvent(this); }

// TimerWheel当中的接口调用了EventLoop当中的接口函数，在类外实现
void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb));
}
void TimerWheel::TimerFlush(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerFlushInLoop, this, id));
}
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
}

class Connection;
//对通信连接的整体管理，关闭连接、发送数据、协议切换、启动 取消非活跃连接释放功能，通过Connection来管理 Channel 当中的回调函数
//以及缓冲区的管理;
//使用智能指针管理Connection 对象，这样就能保证任意一个地方对Cnonection对象进行操作的时候保存了一份shared_ptr ， 不会导致对不存在的连接进行操作
using PtrConnection = std::shared_ptr<Connection>;
typedef enum{DISCONNECTED, CONNECTED ,CONNECTING, DISCONNECTING} ConnStatu;
//连接关闭 连接建立完成 连接创立成功等待处理
class Connection : public std::enable_shared_from_this<Connection>
{
private:
    uint64_t _conn_id;//连续的唯一ID，便于连接的管理和查找,定时器(时间轮中的任务id)id也使用这个
    int _sockfd;//文件描述符
    bool _enable_inactive_release;//标志位表示连接不活跃是否要关闭
    EventLoop* _loop;//链接需要关联一个eventloop,接口操作调用eventloop当中的RunInLoop函数
    ConnStatu _statu;//当前连接所处于的状态
    Socket _socket;//套接字操作管理
    Channel _channel;//连接的事件管理
    Buffer _in_buffer;//输入缓冲区
    Buffer _out_buffer;//输出缓冲区
    Any _context;//使用实现的Any类型来存放请求的上下文

    //一系列回调函数,服务器模块设置，组件使用者调用的函数222
    using ConnectedCallback = std::function<void(const PtrConnection&)>;
    using MessageCallback = std::function<void(const PtrConnection& , Buffer*)>;
    using CloseCallback = std::function<void(const PtrConnection&)>;
    using AnyEventCallback =  std::function<void(const PtrConnection&)>;
    ConnectedCallback _connected_callback;//对创建连接设置的函数
    MessageCallback _message_callback;
    CloseCallback _closed_callback;
    AnyEventCallback _event_callback;

    CloseCallback _server_closed_callback;//服务器内部移除连接的函数
private:
    //描述符触发挂断事件
    void HandleClose()
    {
        //在此之前先判断是否还有数据需要处理，处理完再关闭
        if(_in_buffer.ReadAbleSize() > 0)
        {
            //调用数据处理函数处理数据
            //shared_from_this 总对象自身获取智能指针，当前类需要继承模版类std::enable_shared_from_this<Connection> 才可以使用
            _message_callback(shared_from_this() , &_in_buffer);
        }
        //然后再关闭连接
        return Release();
    }
    //触发文件描述符出错事件
    void HandleError()
    {
        //关闭连接，直接调用HandleClose
        return HandleClose();
    }
    void HandleEvent()
    {
        //如果设置了非活跃连接释放就刷新任务
        if(_enable_inactive_release==true) _loop->TimerFlush(_conn_id);
        //调用_event_callback函数
        if(_event_callback) _event_callback(shared_from_this());
    }
    //连接获取之后，需要对连接进行处理
    void EstablishedInLoop()
    {
        DBG_LOG("开始设置连接状态z:%d" , _sockfd);
        //修改连接状态，启动对新连接的读事件关心 调用回调函数
        assert(_statu == CONNECTING);
        _statu = CONNECTED;
        _channel.EnableRead();
        DBG_LOG("设置连接状态:%d" , _sockfd);
        if(_connected_callback) _connected_callback(shared_from_this());
    }

    //实际的释放接口
    void ReleaseInLoop()
    {
        //修改连接状态为DISCONNECTED
        _statu = DISCONNECTED;
        DBG_LOG("移除连接:%d", _sockfd);
        //移除对于这个连接在epoll当中的关心
        _channel.Remove();
        //关闭这个文件描述符
        _socket.Close();
        // DBG_LOG("1");
        //如果当前时间轮当中有其任务，取消
        if(_loop->HasTimer(_conn_id)) CancelInactiveReleaseInLoop();
        // DBG_LOG("2");
        //调用关闭连接之后的回调函数，避免先移除服务器管理连接信息而导致Connection被释放
        if(_closed_callback) _closed_callback(shared_from_this());
        // DBG_LOG("3");
        //移除服务器当中该连接的相关信息
        if(_server_closed_callback) _server_closed_callback(shared_from_this());
        // DBG_LOG("4");
    }

    //将数据拷贝至发送缓冲区，开启写事件关心
    void SendInLoop(Buffer& buf)
    {
        if(_statu == DISCONNECTED) return;
        //调用Buffer当中的写入函数
        _out_buffer.WriteBufferAndPush(buf);
        //没有对其写事件进行关心变设置
        if(_channel.WriteAble() == false)
        {
            _channel.EnableWrite();
        }
    }
    //也是关闭连接，但需要判断发送缓冲区当中是否有数据需要发送、接收缓冲区当中是否有数据需要处理，之后再关闭连接
    void ShutdownInLoop()
    {
        _statu = DISCONNECTED;//设置连接状态
        //判断缓冲区
        if(_in_buffer.ReadAbleSize() > 0)
        {
            if(_message_callback) _message_callback(shared_from_this() , &_in_buffer);
        }
        if(_out_buffer.ReadAbleSize() > 0)//设置写关心
        {
            if(_channel.WriteAble()== false); _channel.EnableWrite();
        }
        //也不知道需要处理发送缓冲区的数据多少次，当为空就释放连接
        if(_out_buffer.ReadAbleSize() == 0)
        {
            Release();
        }
    }
    //启动 取消非活跃连接
    void EnableInactiveReleaseInLoop(int sec)
    {
        //将Connection当中的_enable_inactive_release 标志位设置为true,将当前连接的Release 封装成一个任务放入时间轮当中
        _enable_inactive_release = true;
        //判断当前定时任务是否存在，不存在则添加，存在则刷新这个定时任务
        if(_loop->HasTimer(_conn_id))
        {
            _loop->TimerFlush(_conn_id);
        }
        else{
            _loop->TimerAdd(_conn_id , sec , std::bind(&Connection::Release, this));
        }
    }
    void CancelInactiveReleaseInLoop()
    {
        //将标志位设置为false,如果该任务在定时器中存在则将其取消
        _enable_inactive_release = false;
        if(_loop->HasTimer(_conn_id))
        {
            _loop->TimerCancle(_conn_id);
        }
    }
    //处理读、写，将这五个函数设置进Channel当中
    //这个函数的fd 读事件就绪之后会调用的函数，接收到的数据放在缓冲区当中，然后调用_message_callback
    void HandleRead()
    {
        //1、从socket 当中获取数据放在接收缓冲区当中
        char buffer[1024];
        ssize_t ret = _socket.NonBlockRecv(buffer , sizeof(buffer)-1);
        //出错了就将连接关闭
        if(ret < 0)
        {
            return ShutdownInLoop();
        }
        //ret为0表示没有读取到数据
        //将buffer 当中当中的数据放入输入缓冲区之中
        _in_buffer.WriteAndPush(buffer , ret);
        //调用_message_callback进行业务处理,在接收缓冲区有数据的情况下
        if(_in_buffer.ReadAbleSize()>0)
        {
            _message_callback(shared_from_this() , &_in_buffer);
        }
    }
    //写
    void HandleWrite()
    {
        //将发送缓冲区中的数据发送出去就可以了
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReadPostion() ,_out_buffer.ReadAbleSize());
        if(ret < 0)
        {
            //发送错误，直接关闭连接;在此之前检查接收缓冲区有没有数据需要处理
            if(_in_buffer.ReadAbleSize() > 0) 
            {
                _message_callback(shared_from_this() , &_in_buffer);
            }
            return Release();
        }
        //让读指针向后移动
        _out_buffer.MoveReadOffset(ret);
        //数据发送成功，但是不知道需要发送多少次，当发送缓冲区为空就关闭对写事件的关心
        if(_out_buffer.ReadAbleSize() ==0)
        {
            _channel.DisableWrite();
            //与释放连接结合，当状态为DISCONNECTED并且发送发送缓冲区中的数据为0，就释放连接
            if(_statu == DISCONNECTED)
            {
                return Release();
            }
        }
    }
    //协议的切换，改变了其当前上下文数据以及处理函数，那么协议自然也就变了
    void UpgradeInLoop(const Any& context  ,
     const ConnectedCallback& conn ,
     const MessageCallback& msg ,
      const CloseCallback &closed,
       const AnyEventCallback &event)
    {
        _context = context;
        _connected_callback = conn;
        _message_callback = msg;
        _closed_callback = closed;
        _event_callback = event;
    }
public:
    //构造,eventloop对象、_conn_id sockfd 需要传递进来
    Connection(EventLoop* loop, uint64_t conn_id , int sockfd)
    :_conn_id(conn_id),_sockfd(sockfd),_enable_inactive_release(false)
    ,_loop(loop),_statu(CONNECTING),_socket(sockfd),_channel(loop,sockfd)
    {
        //设置Chnnel的回调函数
        _channel.SetReadCallback(std::bind(&Connection::HandleRead , this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite , this));
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose , this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError , this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent , this));
    }
    ~Connection(){}

    //向外提供的接口函数
    int Fd()
    {
        return _sockfd;
    }
    int Id()
    {
        return _conn_id;
    }
    //查看当前连接是否处于CONNECTED状态
    bool Connected() { return _statu == CONNECTED;}
    //设置上下文
    void SetContext(const Any& context) {_context = context;}
    //获取上下文数据，返回指针
    Any* GetContext(){ return &_context;}
    //设置那四个回调函数
    void SetConnectedCallBack(const ConnectedCallback& cb) {_connected_callback = cb;}
    void SetMessageCallBack(const MessageCallback& cb){ _message_callback = cb;}
    void SetCloseCallBack(const CloseCallback& cb){_closed_callback=cb;}
    void SetEventCallBack(const AnyEventCallback& cb) {_event_callback = cb;}
    void SetServerCloseCallBack(const CloseCallback& cb){_server_closed_callback= cb;}
    //建立连接过后，进行Channel回调
    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop , this ));
    }
    //发送数据，将数据放入发送缓冲区当中并开辟写事件关心
    void Send(const char*data , size_t len)//外界传入的数据可能是一个临时变量，我们现在的操作是将任务放入任务池当中
    {
        //所以需要使用变量存储一个所要写入的数据
        Buffer buf;
        buf.WriteAndPush(data , len);
        //将任务放入EvnentLoop当中搞得任务队列中
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this , std::move(buf)));
    }
    //将连接关闭的接口，在关闭之前需要判断是否有数据需要处理，有的话先处理再关闭连接
    void Shutdown()
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this ));
    }
    void Release()
    {
        _loop->RunInLoop(std::bind(&Connection::ReleaseInLoop, this));
    }
    void EnableInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop,this , sec));
    }
    void CancelInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop,this));
    }
    //协议切换
    void Upgrade(const Any&context ,
    const ConnectedCallback& conn ,
     const MessageCallback& msg ,
      const CloseCallback &closed,
       const AnyEventCallback &event)
    {
        //首先确保这个操作一定是在当前线程中进行的
        _loop->AssertInLoop();
        //实则就是调用UpgradeInLoop,将其放入loop中的任务队列里
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop,this , context , conn, msg , closed,event));
    }
};


//将Socket与Channel 合并起来管理
//对监听套接字单独实现一个模块
//对于新连接如何处理由服务器来决定，所以需要回调函数
class Acceptor
{
private:
    Socket _socket;//保存监听套接字
    EventLoop* _loop;//对监听事件进行监控
    Channel _channel;//对套接字进行管理

    //设置一个回调函数
    using AcceptCallback = std::function<void(int)>;
    AcceptCallback _accept_callback;
private:
    //对监听套接字的读事件回调函数，获取新连接，调用_accept_callback 进行新连接处理
    void HandleRead()
    {
        //获取新连接，调用_accept_callback函数
        int newfd = _socket.Accept();
        if(newfd < 0) return;
        if(_accept_callback) _accept_callback(newfd);
    }
    int CreateServer(int port)
    {
        //创建监听套接字并且返回其文件描述符
        bool ret = _socket.CreateServer(port);
        assert(ret == true);
        return _socket.fd();
    }
public:
    Acceptor(EventLoop* loop , int port)
    :_socket(CreateServer(port))
    ,_loop(loop)
    ,_channel(_loop , _socket.fd())
    {
        //设置回调函数
        _channel.SetReadCallback(std::bind(&Acceptor::HandleRead , this));
    }
    ~Acceptor(){}
    void SetAcceptCallback(const AcceptCallback& cb)
    {
        _accept_callback = cb;
    }
    void Listen()
    {
        _channel.EnableRead();//关心读事件
    }
};  

//将EventLoop与线程结合起来
//记录线程id ;EventLoop模块在构造的时候，就会初始化_thread_id,此时只需要用当前线程id 比较eventloop对象中存储的线程id就可以判断是否在对应的线程当中执行
//需要先创建线程然后绑定对应的eventloop对象
class LoopThread
{
private:
    std::mutex _mutex;
    std::condition_variable _cond;
    EventLoop* _loop;
    std::thread _thread;//线程
private:
    void ThreadEntry()
    {
        EventLoop loop;//让loop的生命周期随线程
        //实例化EventLoop对象，并且开始运行eventloop中的功能  --> 只能在线程中进行实力哈
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _loop = &loop;
            _cond.notify_all();//唤醒
        }
        loop.Start();//就绪事件处理
    }
public:
    //构造函数
    LoopThread()
    :_loop(nullptr)
    ,_thread(std::thread(&LoopThread::ThreadEntry,this))//创建线程设定线程的入口函数
    {}
    ~LoopThread(){}
    //返回当前线程所关联的eventloop对象指针
    EventLoop* GetLoop()
    {
        EventLoop* loop = nullptr;
        {
            //当线程正在创建的时候但是并未实例化，而此时外界调用GetLoop接口就无法获取指向EventLoop
            //对象的指针，此时需要设置锁和条件变量，_loop为临界资源
            std::unique_lock<std::mutex> lock(_mutex);
            _cond.wait(lock , [&](){return _loop!=nullptr;});
            loop = _loop;//保证_loop的线程安全，使用临时变量保存
        }
        return loop;
    }
};

//针对所有LoopThread 设计出一个线程池，对所有的线程进行管理
//主从Reactor 模型，主线程负责新连接的获取，从属线程负责新连接的事件关心、处理
class LoopThreadPool//管理0个或者多个LoopThread 对象
{
//主线程获取到了新连接，需要将新连接挂到从属线程上进行事件关心与处理；如果没有从属线程，那么获取的新连接直接在
//主线程所对应的eventloop上进行管理；
//对于多个线程，此处采用轮转的思想
private:
    int _thread_count;//从属线程的数量
    int _next_loop_idx;//下一个挂接连接的线程
    EventLoop* _baseloop;//主线程的eventloop指针，用来获取连接
    std::vector<LoopThread*> _threads;//保存所有从属线程
    std::vector<EventLoop*> _loops;//保存所有从属线程所对应的EventLoop对象以便于连接的分配
public:
    //主线程是在外面创建的，所以_baseloop需要传参进来；而LoopThreadPool是用来管理所有的从属线程
    LoopThreadPool(EventLoop* loop)
    :_thread_count(0)
    ,_next_loop_idx(0)
    ,_baseloop(loop)
    {}
    ~LoopThreadPool(){}
    void SetThreadCount(int count)//设置线程的数量
    {
        _thread_count = count;
    }   
    void Create()//创建所有的从属线程
    {
        //初始化_loops 与 threads ， 创建_threads_count 个LoopThread 对象并进行管理
        _threads.resize(_thread_count);
        _loops.resize(_thread_count);
        for(int i = 0;i<_thread_count;i++)
        {
            _threads[i] = new LoopThread();
            _loops[i] = _threads[i]->GetLoop();//此处就不用担心会获取失败了
            //因为在GetLoop的逻辑当中设置了互斥锁与条件变量
        }
        return;
    }
    EventLoop* NextLoop()//下一个线程的eventloop指针
    {
        //如果没有从属线程就返回主线程
        if(_thread_count==0) return _baseloop;
        //让_next_loop_idx 先后走一步，返回_loops 中对应位置的数据
        _next_loop_idx = (_next_loop_idx +1) % _thread_count;
        return _loops[_next_loop_idx];
    }

};

//TcpServer模块。对所有模块的整合
//Acceptor 对象创建监听套接字；EventLoop，baseloop对象实现对监听套接字的关心
//std::unordered_map<uint64_t,PtrConnection> _conns;实现对所有新建连接的管理
//LoopThreadpool 创建线程池，使得线程与eventloop一一对应,对新连接进行关心、事件就绪处理
class TcpServer
{
private:
    uint64_t _next_id;//自动增长记录连接id的成员变量
    int _port;
    int _timeout;//非活跃连接释放的时间
    bool _enable_inactive_release;//是否启动了非活跃连接释放功能
    Acceptor _acceptor;//监听套接字的管理对象
    EventLoop _baseloop;//监听套接字的监听对象
    LoopThreadPool _pool;//从属套接字，新连接的监听、管理
    std::unordered_map<uint64_t,PtrConnection> _conns;//保管所有套接字的shread_ptr 对象

    //需要设置一些回调函数到Connetion当中
    using ConnectedCallback = std::function<void(const PtrConnection&)>;
    using MessageCallback = std::function<void(const PtrConnection& , Buffer*)>;
    using CloseCallback = std::function<void(const PtrConnection&)>;
    using AnyEventCallback = std::function<void(const PtrConnection&)>;
    using Functor = std::function<void()>;

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    CloseCallback _close_callback;
    AnyEventCallback _event_callback;
private:
    void RunAfterInLoop(const Functor& cb , int delay)//添加定时任务
    {
        _next_id++;
        _baseloop.TimerAdd(_next_id , delay , cb);
    }
    //为新连接创建Connection来进行管理
    void NewConnection(int fd)
    {
        _next_id++;
        PtrConnection conn(new Connection(_pool.NextLoop(), _next_id,fd));
        //为新连接设置对应的回调函数
        conn->SetConnectedCallBack(_connected_callback);
        conn->SetMessageCallBack(_message_callback);
        conn->SetServerCloseCallBack(_event_callback);
        conn->SetCloseCallBack(std::bind(&TcpServer::RemoveConnectionInLoop, this , std::placeholders::_1));
        conn->SetEventCallBack(_event_callback);
        //启动连接不活跃就销毁功能
        if(_enable_inactive_release) conn->EnableInactiveRelease(_timeout);
        //就绪初始化
        conn->Established();//修改连接状态，启动对新连接的读事件关心 调用回调函数
        //将这个新连接插入进管理连接的哈希表当中
        _conns.insert(std::make_pair(_next_id , conn));
        DBG_LOG("添加新连接: %d---------------" , fd);
    }

    //从_conns中移除对应的连接
    void RemoveConnectionInLoop(const PtrConnection& conn)
    {
        int id = conn->Id();
        auto it = _conns.find(id);
        if(it == _conns.end()) return;
        _conns.erase(it);
        DBG_LOG("移除 connection...");
    }
    void RemoveConnection(const PtrConnection& conn)
    {
        _baseloop.RunInLoop(std::bind(&TcpServer::RemoveConnection, this , conn));
    }
public:
    TcpServer(int port)
    :_next_id(0)
    ,_port(port)
    ,_timeout(0)
    ,_enable_inactive_release(false)
    ,_acceptor(&_baseloop , port)
    ,_pool(&_baseloop)
    {
        //设置监听套接字的回调函数并关心其读事件
        _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection,this ,std::placeholders::_1));
        _acceptor.Listen();
    }
    ~TcpServer(){}
    void SetThreadCount(int count) 
    {
        //调用LoopThreadPool当中搞得SetThreadCount
        _pool.SetThreadCount(count);
    }
    //设置4个回调函数
    void SetConnectedCallback(const ConnectedCallback& cb) {_connected_callback = cb;};
    void SetMessageCallback(const MessageCallback& cb) {_message_callback = cb;};
    void SetCloseCallback(const CloseCallback& cb) {_close_callback = cb;};
    void SetAnyEventCallback(const AnyEventCallback& cb) {_event_callback = cb;};

    //启动非活跃连接释放功能
    void EnableInactiveRelease(int sec)
    {
        _timeout = sec;
        _enable_inactive_release = true;
    };

    //添加定时任务
    void RunAfter(const Functor& task ,int delay)
    {
        _baseloop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop , this , task, delay));
    }

    void Start()
    {
        _pool.Create();//创建线程池
        _baseloop.Start();
    }
};

class NetWork
{
public:
    NetWork()
    {
        DBG_LOG("SIGPIPE INIT");
        signal(SIGPIPE , SIG_IGN);
    }
};

static NetWork nw;

